﻿using Modbus.Device;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using ModbusTest.Base;
using ModbusTest.Models;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrackBar;

namespace ModbusTest.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        //Nmodbus4
        IModbusSerialMaster master { get; set; }

        //模拟器
        Random random = new Random();

        public event PropertyChangedEventHandler? PropertyChanged;

        private SerialPort serialPort = new SerialPort();
        private LogProvider LogProvider;

        //是否启动模拟
        private bool _isMoni;

        public bool Moni
        {
            get { return _isMoni; }
            set { _isMoni = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Moni"));
            }
        }


        //开启监控
        private bool _isStart;

        public bool IsStart
        {
            get { return _isStart; }
            set
            {
                _isStart = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsStart"));

                if (!value)
                    this.ShowMessage("监控未开始，请打开监控开关");
            }
        }

        //开启日志
        private bool _isLog;

        public bool IsLog
        {
            get { return _isLog; }
            set
            {
                _isLog = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsLog"));
            }
        }

        //界面模糊
        private int _blurRadius = 0;

        public int BlurRadius
        {
            get { return _blurRadius; }
            set
            {
                _blurRadius = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("BlurRadius"));
            }
        }


        //x轴时间
        private DateTime _currentDate;

        public DateTime CurrentDate
        {
            get { return _currentDate; }
            set
            {
                _currentDate = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentDate"));
            }
        }


        //连接信息
        private string _message;

        public string Message
        {
            get { return _message; }
            set
            {
                _message = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Message"));
            }
        }
        //信息颜色
        private string _msgColor = "#90EE90";

        public string MsgColor
        {
            get { return _msgColor; }
            set
            {
                _msgColor = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MsgColor"));
            }
        }

        //端口名称
        public string PortName { get; set; }
        public List<string> PortNameList { get; set; }

        //波特率
        public int BaudRate { get; set; } = 9600;
        public List<int> BaudRateList { get; set; } =
            new List<int> { 4800, 9600, 14400, 19200, 38400, 56000, 57600, 115200, 128000, 256000 };

        //Log地址
        private string _logPath;

        public string LogPath
        {
            get { return _logPath; }
            set
            {
                _logPath = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LogPath"));
            }
        }


        public Command ConfigCommand { get; set; }
        public Command ConfigCloseCommand { get; set; }
        public Command LogPathSelectCommand { get; set; }
        public Command OpenLogPathCommand { get; set; }

        public List<ItemModel> ItemList { get; set; }
        private List<Task> tasks = new List<Task>();
        private CancellationTokenSource cts = new CancellationTokenSource();


        public MainViewModel()
        {
            // 配置数据的初始化
            try
            {
                //读取配置文件
                string json = File.ReadAllText("config.json");
                Config config = System.Text.Json.JsonSerializer.Deserialize<Config>(json);
                this.PortName = config.PortName;
                this.BaudRate = config.BaudRate;
                this.LogPath = config.LogPath;
            }
            catch (Exception ex)
            {
                this.ShowMessage("初始化参数加载失败，" + ex.Message, false);
                return;
            }

            LogProvider = new LogProvider(this.LogPath);

            ItemList = new List<ItemModel>();
            ItemList.Add(new ItemModel() { SlaveId = 1 });
            ItemList.Add(new ItemModel() { SlaveId = 2 });
            ItemList.Add(new ItemModel() { SlaveId = 3 });
            ItemList.Add(new ItemModel() { SlaveId = 4 });

            //刷新当前时间
            var task = Task.Run(async () =>
            {
                while (!cts.IsCancellationRequested)
                {
                    CurrentDate = DateTime.Now;
                    await Task.Delay(new TimeSpan(1, 0, 0));
                }
            }, cts.Token);
            tasks.Add(task);
            
            //获取所有串口名称
            PortNameList = SerialPort.GetPortNames().ToList();


            ConfigCommand = new Command(Config);
            ConfigCloseCommand = new Command(ConfigClose);
            LogPathSelectCommand = new Command(LogPathSelect);
            OpenLogPathCommand = new Command(OpenLogFolder);

            //核心
            this.StartMonitor();
            MoniData();
        }
        private void Config()
        {
            IsStart = false;
            serialPort.Close();
            BlurRadius = 10;
        }
        private void ConfigClose()
        {
            BlurRadius = 0;

            // 数据保存的动作
            try
            {
                Config config = new Config();
                config.PortName = this.PortName;
                config.BaudRate = this.BaudRate;
                config.LogPath = this.LogPath;

                //写入配置文件
                var json = System.Text.Json.JsonSerializer.Serialize(config);
                File.WriteAllText("config.json", json);

                LogProvider.WriteLog("配置文件修改完成", this.IsLog);
            }
            catch (Exception ex)
            {
                LogProvider.WriteLog("写配置文件失败！" + ex.Message, this.IsLog, isError: true);
                this.ShowMessage("写配置文件失败！" + ex.Message, false);
            }

        }
        //选择Log地址
        private void LogPathSelect()
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            var result = folderDialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                this.LogPath = folderDialog.SelectedPath;

                LogProvider.LogPath = this.LogPath;
            }
        }

        private void OpenLogFolder()
        {
            if (Directory.Exists(this.LogPath))
            {
                Process.Start("explorer.exe", this.LogPath);
            }
        }

        //循环监控，如果isstart打开了就一直读取数据
        private void StartMonitor()
        {
            var task = Task.Factory.StartNew(async () =>
            {
                while (!cts.IsCancellationRequested)
                {
                    await Task.Delay(400);

                    if (!IsStart) continue;

                    //判断串口是否打开，如果没有打开就open一下
                    bool state = serialPort.IsOpen;
                    if (!state)
                    {
                        state = OpenSerial();
                    }
                    if (state)
                    {
                        this.ShowMessage("串口打开正常！");
                        try
                        {
                            foreach (var item in this.ItemList)
                            {
                                //传递itemModel进来，以及初始化了从站地址
                                await this.Read(item);
                            }
                        }
                        catch (Exception ex)
                        {
                            LogProvider.WriteLog("读取寄存器失败！" + ex.Message, this.IsLog, isError: true);
                            this.ShowMessage("读取寄存器失败！" + ex.Message, false);
                        }
                    }
                }
            }, cts.Token);
            tasks.Add(task);
        }

        //开启串口
        private bool OpenSerial()
        {
            try
            {
                serialPort.PortName = this.PortName;
                serialPort.BaudRate = this.BaudRate;

                serialPort.Open();

                LogProvider.WriteLog("串口打开成功", this.IsLog);
                master = ModbusSerialMaster.CreateRtu(serialPort);
                return true;
            }
            catch (Exception ex)
            {
                LogProvider.WriteLog("串口打开失败！" + ex.Message, this.IsLog, isError: true);
                this.ShowMessage("串口打开失败！" + ex.Message, false);
                return false;
            }
        }


        //核心，读取数据
        private async Task Read(ItemModel model)
        {
            try
            {
               await Task.Delay(100);
                //=================利用NModbus4读取===========================
                var temp1 = master.ReadHoldingRegisters((byte)model.SlaveId, 0, 2);
                if (temp1 != null&&temp1.Length>0)
                {
                    model.Temperature = temp1[0] * 0.1;
                    model.Humidity = temp1[1] * 0.1;
                    LogProvider.WriteLog($"从站[{model.SlaveId}]数据获取成功 - {temp1[0] * 0.1}/{temp1[1] * 0.1}", this.IsLog);
                }
            }
            catch (Exception ex)
            {
                LogProvider.WriteLog($"从站[{model.SlaveId}]数据获取失败！" + ex.Message, this.IsLog);
                throw ex;
            }
        }
        
        //模拟数据写入
        public void MoniData()
        {
            try
            {
                Task.Run(async () =>
                {
                    while (true)
                    {
                        await Task.Delay(1000);
                        if (Moni && serialPort.IsOpen)
                        {
                            foreach (var item in ItemList)
                            {
                                master.WriteSingleRegisterAsync((byte)item.SlaveId, 0, (ushort)random.Next(1, 300));
                                master.WriteSingleRegisterAsync((byte)item.SlaveId, 1, (ushort)random.Next(500, 801));
                            }
                        }
                    }
                });
            }
            catch (Exception ex)
            {

                throw;
            }
        }


        
        private void ShowMessage(string message, bool state = true)
        {
            this.Message = message;
            this.MsgColor = state ? "#90EE90" : "#FF4500";
        }

        public void Dispose()
        {
            cts.Cancel();
            Task.WaitAll(tasks.ToArray(), 10000);

            serialPort.Close();

            LogProvider.WriteLog("对象已释放，已销毁", this.IsLog);
            LogProvider.Dispose();
        }
    }
}
